package main

import (
	"database/sql"
	"fmt"
	"github.com/go-sql-driver/mysql"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"strings"
	"unicode/utf8"
)

var router = mux.NewRouter()
var db *sql.DB

//初始化数据库连接
func initDB()  {
	var err error
	config := mysql.Config{
		User: "root",
		Passwd: "",
		Addr: "127.0.0.1:3306",
		Net: "tcp",
		DBName: "goblog",
		AllowNativePasswords: true,
	}
	//数据库连接池
	db, err := sql.Open("mysql", config.FormatDSN())
	checkError(err)
	//设置最大连接数
	db.SetMaxOpenConns(25)
	//设置最大空闲连接数
	db.SetConnMaxIdleTime(25)
	//设置每个链接的过期时间
	//db.SetConnMaxLifetime(5 * time.Minute)
	//尝试连接
	err = db.Ping()
	checkError(err)
}

//创建表
func createTables() {
	fmt.Println(1)
	//createArticlesSQL := `CREATE TABLE IF NOT EXISTS articles(
	//		id bigint(20) PRIMARY KEY AUTO_INCREMENT NOT NULL,
	//		title varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
	//		body longtext COLLATE utf8mb4_unicode_ci
	//	);`
	log.Fatal(db)
	//_, err := db.Exec(createArticlesSQL)
	//checkError(err)
}

//检查错误
func checkError(err error)  {
	if err != nil {
		log.Fatal(err)
	}
}

//home page
func homeHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "text/html; charset=utf-8")
	fmt.Fprint(w, "<h1>Hello, 欢迎来到 goblog！</h1>")
}

//about page
func aboutHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "text/html; charset=utf-8")
	fmt.Fprint(w, "如您有问题反馈或建议，请联系" + "<a href=\"mailto:872577523@qq.com\">872577523@qq.com</a>")
}

//articlesIndex
func articlesIndexHandles(w http.ResponseWriter, r *http.Request)  {
	fmt.Fprint(w, "文章首页")
}

//articlesShow
func articlesShowHandles(w http.ResponseWriter, r *http.Request)  {
	vars := mux.Vars(r)
	id := vars["id"]
	fmt.Fprint(w, "文章详情页", id)
}

//articlesStore
type ArticlesFormData struct {
	Title, Body	string
	URL *url.URL
	Errors map[string]string
}
func articlesStoreHandles(w	http.ResponseWriter, r *http.Request)  {
	parse := r.ParseForm()
	if parse != nil {
		//解析错误
		fmt.Fprint(w, "请提供正确的数据")
	}
	errors := make(map[string]string)
	title := r.PostFormValue("title")
	body := r.PostFormValue("body")
	if title == "" {
		errors["title"] = "标题不能为空"
	} else if utf8.RuneCountInString(title) > 40 || utf8.RuneCountInString(title) < 3 {
		errors["title"] = "标题长度需在3~40之间"
	}
	if body == "" {
		errors["body"] = "内容不能为空"
	} else if utf8.RuneCountInString(body) > 10 {
		errors["body"] = "内容需要大于10个字节"
	}

	if len(errors) == 0 {
		//验证通过
	} else {
		//验证失败
		storeURL,_ := router.Get("articles.store").URL()
		data := ArticlesFormData{
			Title: title,
			Body: body,
			URL: storeURL,
			Errors: errors,
		}
		//初始化模板
		tmpl, err := template.ParseFiles("resources/views/articles/create.gohtml")
		if err != nil {
			panic(err)
		}
		tmpl.Execute(w, data)
	}
}

//创建博文表单
func articlesCreateHandles(w http.ResponseWriter, r *http.Request)  {
	storeUrl,_ := router.Get("articles.store").URL()
	data := ArticlesFormData{
		Title:  "",
		Body:   "",
		URL:    storeUrl,
		Errors: nil,
	}
	tmpl, err := template.ParseFiles("resources/views/articles/create.gohtml")
	if err != nil {
		panic(err)
	}

	tmpl.Execute(w, data)
}

//notFound
func notFoundHandler(w http.ResponseWriter, r *http.Request)  {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprint(w, "<h1>请求页面未找到</h1>")
}

//强制内容类型为 HTML
func forceHTMLMiddleware(h http.Handler) http.Handler  {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//设置标头
		w.Header().Set("Content-type", "text/html; charset=utf-8")
		//继续处理请求
		h.ServeHTTP(w, r)
	})
}

//移除链接后的 反斜杠(/)
func removeTrailingSlash(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			r.URL.Path = strings.TrimSuffix(r.URL.Path, "/")
		}
		next.ServeHTTP(w, r)
	})
}

//main
func main() {
	initDB()
	createTables()
	router.HandleFunc("/", homeHandler).Methods("GET").Name("home")
	router.HandleFunc("/about", aboutHandler).Methods("GET").Name("about")
	router.HandleFunc("/articles", articlesIndexHandles).Methods("GET").Name("articles.index")
	router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandles).Methods("GET").Name("articles.show")
	router.HandleFunc("/articles", articlesStoreHandles).Methods("POST").Name("articles.store")
	router.HandleFunc("/articles/create", articlesCreateHandles).Methods("GET").Name("articles.create")

	//自定义404页面
	router.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	//中间件：强制内容类型为 HTML
	router.Use(forceHTMLMiddleware)

	http.ListenAndServe(":3000", removeTrailingSlash(router))
}

